/**
  ******************************************************************************
  * @author     Chris
  * @since      2023/10/11 13:57
  *
  * @file       pd_h_timer.c
  * @brief      Hardware Peripheral Driver of TIM.
  *
  * @note       This file contains the hardware peripheral driver of TIM.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date           Author       Notes
  *   2023/10/11     Chris        the first version
  *
  ******************************************************************************
  */

#include <stdio.h>

#include "stm32g4xx_ll_bus.h"
#include "stm32g4xx_ll_tim.h"
#include "pd_h_gpio.h"
#include "stm32g4xx_ll_gpio.h"

/** region Declaration and Definition Region */


/** region Variables and Constants Region */

/** endregion Variables and Constants Region */


/** region Function Declaration Region */

/** endregion Function Declaration Region */


/** endregion Declaration and Definition Region */


/** region Public Definition Region */
/**
 * @brief   定时器 2 初始化（内部时钟源定时功能）
 *
 * @note    TIM 定时功能：
 *          定时时间 = 1 / 计数器溢出频率 = (PSC + 1)*(ARR + 1) / CK_PSC
 * @retval  无
 */
void PD_H_TIM2_TimerInit(void) {
    // 使能时钟
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
    // 设置内部时钟模式
    LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);

    // 时基单元配置
    LL_TIM_InitTypeDef TIM_InitStruct = {0};
    TIM_InitStruct.Prescaler = 17000 - 1;
    TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
    TIM_InitStruct.Autoreload = 10000 - 1;
    TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; // 滤波采样频率的分频系数
    TIM_InitStruct.RepetitionCounter = 0;                     // 重复计数器
    LL_TIM_Init(TIM2, &TIM_InitStruct);

    // 中断输出控制：使能定时器更新中断
    LL_TIM_EnableIT_UPDATE(TIM2);

    // NVIC
    NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(
                         NVIC_GetPriorityGrouping(), 2, 2));
    NVIC_EnableIRQ(TIM2_IRQn);

    // 使能计数器
    LL_TIM_EnableCounter(TIM2);
}


/**
 * @brief   定时器 3 初始化（外部时钟源触发）
 *
 * @note    补充：：
 *          1. 定时时间 = 1 / 计数器溢出频率 = (PSC + 1)*(ARR + 1) / CK_PSC
 *          2. TIM3 的外部触发通道 TIM3_ETR 分别为：
 *             PB3 - AF10
 *             PD2 - AF2
 * @retval  无
 */
void PD_H_TIM3_ETRInit(void) {
    // TIM3 外部触发引脚 GPIO 初始化
    PD_H_GPIO_TIM3_Init();

    // 使能时钟
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);

    // 配置外部触发（ETR）输入
    LL_TIM_ConfigETR(TIM3, LL_TIM_ETR_POLARITY_NONINVERTED, LL_TIM_ETR_PRESCALER_DIV1,
                     LL_TIM_ETR_FILTER_FDIV1);
    // 设置外部时钟模式 2：来自 GPIO 引脚
    LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_EXT_MODE2);

    // 时基单元配置
    LL_TIM_InitTypeDef TIM_InitStruct = {0};
    TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; // 滤波采样频繁的分频系数
    TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
    TIM_InitStruct.Prescaler = 1 - 1;
    TIM_InitStruct.Autoreload = 10 - 1;
    TIM_InitStruct.RepetitionCounter = 0; // 重复计数器
    LL_TIM_Init(TIM3, &TIM_InitStruct);

    // 使能更新中断
    LL_TIM_EnableIT_UPDATE(TIM3);
    // NVIC
    NVIC_SetPriority(TIM3_IRQn, NVIC_EncodePriority(
                         NVIC_GetPriorityGrouping(), 2, 2));
    NVIC_EnableIRQ(TIM3_IRQn);

    // 运行控制
    LL_TIM_EnableCounter(TIM3);       // 使能计数器
    LL_TIM_EnableExternalClock(TIM3); // 使能外部时钟
}

/**
 * @brief   获取定时器 3 的计数值
 *
 * @note    无
 * @retval  无
 */
uint16_t PD_H_TIM3_GetCounter(void) {
    return LL_TIM_GetCounter(TIM3);
}


/**
 * @brief   定时器 TIM4 初始化（输出比较功能实现 PWM）
 *
 * @note    PWM 的相关计算：
 *          首先，通过要求的分辨率，根据下面的公式计算出重装值 ARR：
 *              PWM 分辨率 = 1 / (ARR + 1)
 *          然后，通过要求的频率，根据下面的公式计算出预分频值 PSC：
 *              PWM 频率 = 时钟频率 / (PSC + 1) / (ARR + 1)
 *          最后，通过给定的占空比，根据下面的公式计算出捕获比较寄存器 CCR 的值：
 *              PWM 占空比 = CCR / (ARR + 1)
 *
 *          使用 TIM4 的输出比较实现 PWM，TIM4 的 4 个通道如下：
 *          | PIN  |   AF2    |   AF10   |
 *          |-----------------------------
 *          | PA11 |          | TIM4_CH1 |
 *          | PB6  | TIM4_CH1 |          |
 *          | PD12 | TIM4_CH1 |          |
 *          |-----------------------------
 *          | PA12 |          | TIM4_CH2 |
 *          | PB7  | TIM4_CH2 |          |
 *          | PD13 | TIM4_CH2 |          |
 *          |-----------------------------
 *          | PA13 |          | TIM4_CH3 |
 *          | PB8  | TIM4_CH3 |          |
 *          | PD14 | TIM4_CH3 |          |
 *          |-----------------------------
 *          | PB9  | TIM4_CH4 |          |
 *          | PD15 | TIM4_CH4 |          |
 *          ------------------------------
 * @param   无
 * @retval  无
 */
void PD_H_TIM4_PWMInit(void) {
    // 使能时钟
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM4);

    // 设置内部时钟源
    LL_TIM_SetClockSource(TIM4, LL_TIM_CLOCKSOURCE_INTERNAL);

    // 配置时基单元
    LL_TIM_InitTypeDef TIM_InitStruct = {0};
    TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; // 滤波采样频繁的分频系数
    TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
    TIM_InitStruct.Prescaler = 1700 - 1;  // PSC
    TIM_InitStruct.Autoreload = 100 - 1;  // ARR
    TIM_InitStruct.RepetitionCounter = 0; // 重复计数器
    LL_TIM_Init(TIM4, &TIM_InitStruct);

    // 配置输出比较单元
    LL_TIM_OC_InitTypeDef TIM_OC_InitStruct;
    LL_TIM_OC_StructInit(&TIM_OC_InitStruct);
    TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
    TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_LOW;
    TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE;
    TIM_OC_InitStruct.CompareValue = 0; // CCR
    LL_TIM_OC_Init(TIM4, LL_TIM_CHANNEL_CH1, &TIM_OC_InitStruct);
    LL_TIM_OC_Init(TIM4, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct);
    LL_TIM_OC_Init(TIM4, LL_TIM_CHANNEL_CH3, &TIM_OC_InitStruct);
    LL_TIM_OC_Init(TIM4, LL_TIM_CHANNEL_CH4, &TIM_OC_InitStruct);

    // 其它寄存器使能
    LL_TIM_EnableCounter(TIM4);

    // 配置 GPIO 为复用推挽输出
    PD_H_GPIO_TIM4_Init();
}

/**
 * @brief   修改定时器 4 的 PWM 占空比（通过改变 CCR 的值）
 *
 * @note    PWM 占空比的计算方式：
 *          PWM 占空比 = CCR / (ARR + 1)
 * @param   val 要设置的 CCR 的值
 * @param   channel This parameter can be one of the following values:
 *          @arg @ref LL_TIM_CHANNEL_CH1
 *          @arg @ref LL_TIM_CHANNEL_CH2
 *          @arg @ref LL_TIM_CHANNEL_CH3
 *          @arg @ref LL_TIM_CHANNEL_CH4
 *          @arg @ref LL_TIM_CHANNEL_CH5
 *          @arg @ref LL_TIM_CHANNEL_CH6
 * @retval  无
 */
void PD_H_TIM4_SetPWMDuty(const uint32_t channel, const uint32_t val) {
    switch (channel) {
        case LL_TIM_CHANNEL_CH1:
            LL_TIM_OC_SetCompareCH1(TIM4, val);
            break;
        case LL_TIM_CHANNEL_CH2:
            LL_TIM_OC_SetCompareCH2(TIM4, val);
            break;
        case LL_TIM_CHANNEL_CH3:
            LL_TIM_OC_SetCompareCH3(TIM4, val);
            break;
        case LL_TIM_CHANNEL_CH4:
            LL_TIM_OC_SetCompareCH4(TIM4, val);
            break;
        default:
            break;
    }
}

/**
 * @brief   修改定时器 4 的 PWM 频率（通过改变预分频器 PSC 的值）
 *
 * @note    PWM 的相关计算：
 *          首先，通过要求的分辨率，根据下面的公式计算出重装值 ARR：
 *              PWM 分辨率 = 1 / (ARR + 1)
 *          然后，通过要求的频率，根据下面的公式计算出预分频值 PSC：
 *              PWM 频率 = 时钟频率 / (PSC + 1) / (ARR + 1)
 *          最后，通过给定的占空比，根据下面的公式计算出捕获比较寄存器 CCR 的值：
 *              PWM 占空比 = CCR / (ARR + 1)
 *
 *          各通道的 CCR 共用一个时基单元.
 *
 * @param   val 要设置的频率
 * @retval  无
 */
void PD_H_TIM4_SetPWMFreq(const uint32_t val) {
    // PWM 频率 = 170MHz / (PSC + 1) / (ARR + 1)
    // PSC = 170MHz / val / (ARR + 1) - 1
    LL_TIM_SetPrescaler(TIM4, 1700000 / val - 1);
}


/**
 * @brief   定时器 15 初始化（通过 PWM 实现直流电机控制）
 *
 * @note    约定电机的速度控制在 0~100，即 CCR 的取值范围为 0~100，占空比为 0~100%，
 *          内部时钟频率 CK_PSC 为 170MHz，则由以下公式：
 *              PWM 频率 = CK_PSC / (PSC + 1) / (ARR + 1)
 *              PWM 占空比 = CCR / (ARR + 1)
 *              PWM 分辨率 = 1 / (ARR + 1)
 *          得：
 *              ARR + 1 = 100
 *              PSC + 1 = 1700000
 *
 *          定时器 TIM15 的 2 个通道如下：
 *          | PIN  |   AF1     |    AF2     |    AF3    |   AF9      |
 *          |---------------------------------------------------------
 *          | PA1  |           |            |           | TIM15_CH1N |
 *          | PB15 |           | TIM15_CH1N |           |            |
 *          |---------------------------------------------------------
 *          | PA2  |           |            |           | TIM15_CH1  |
 *          | PB14 | TIM15_CH1 |            |           |            |
 *          | PF9  |           |            | TIM15_CH1 |            |
 *          |---------------------------------------------------------
 *          | PA3  |           |            |           | TIM15_CH2  |
 *          | PB15 | TIM15_CH2 |            |           |            |
 *          | PF10 |           |            | TIM15_CH2 |            |
 *          |---------------------------------------------------------
 * @param   无
 * @retval  无
 */
void PD_H_TIM15_PWMInit(void) {
    // 使能时钟
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM15);

    // 设置内部时钟源
    LL_TIM_SetClockSource(TIM15, LL_TIM_CLOCKSOURCE_INTERNAL);

    // 配置时基单元
    LL_TIM_InitTypeDef TIM_InitStruct = {0};
    TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; // 滤波采样频繁的分频系数
    TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
    TIM_InitStruct.Prescaler = 1700 - 1;  // PSC
    TIM_InitStruct.Autoreload = 100 - 1;  // ARR
    TIM_InitStruct.RepetitionCounter = 0; // 重复计数器
    LL_TIM_Init(TIM15, &TIM_InitStruct);

    // 配置输出比较单元
    LL_TIM_OC_InitTypeDef TIM_OC_InitStruct;
    LL_TIM_OC_StructInit(&TIM_OC_InitStruct);
    TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
    TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
    TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE;
    TIM_OC_InitStruct.CompareValue = 0; // CCR
    LL_TIM_OC_Init(TIM15, LL_TIM_CHANNEL_CH1, &TIM_OC_InitStruct);
    LL_TIM_OC_Init(TIM15, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct);

    // 配置 GPIO
    // 配置 PA2、PA3 的 AF9 为 TIM15_CHx 的输出引脚
    // 设置 PA4、5、6、7 为推挽输出，以控制电机芯片的双路输出
    PD_H_GPIO_TIM15_Init();

    // 其它寄存器使能
    LL_TIM_EnableCounter(TIM15);
    LL_TIM_EnableAllOutputs(TIM15); // TIM15 比 TIM2 多了一个 DTG（死区电压生成）
}

/**
 * @brief   修改定时器 15 的 PWM 占空比（通过设置 CCR 的值）
 *
 * @note
 * @param   channel 待设置的通道
 * @param   val 输出比较值。取值范围为 -100~100
 * @retval  无
 */
void PD_H_TIM15_SetPWMDuty(const uint32_t channel, const int8_t val) {
    switch (channel) {
        case LL_TIM_CHANNEL_CH1:
            if (val >= 0) {
                PD_H_GPIO_WriteBit(GPIOA, LL_GPIO_PIN_4, SET);
                PD_H_GPIO_WriteBit(GPIOA, LL_GPIO_PIN_5, RESET);
                LL_TIM_OC_SetCompareCH1(TIM15, val);
            }
            else {
                PD_H_GPIO_WriteBit(GPIOA, LL_GPIO_PIN_4, RESET);
                PD_H_GPIO_WriteBit(GPIOA, LL_GPIO_PIN_5, SET);
                LL_TIM_OC_SetCompareCH1(TIM15, -val);
            }
            break;
        case LL_TIM_CHANNEL_CH2:
            if (val >= 0) {
                PD_H_GPIO_WriteBit(GPIOA, LL_GPIO_PIN_6, SET);
                PD_H_GPIO_WriteBit(GPIOA, LL_GPIO_PIN_7, RESET);
                LL_TIM_OC_SetCompareCH2(TIM15, val);
            }
            else {
                PD_H_GPIO_WriteBit(GPIOA, LL_GPIO_PIN_6, RESET);
                PD_H_GPIO_WriteBit(GPIOA, LL_GPIO_PIN_7, SET);
                LL_TIM_OC_SetCompareCH1(TIM15, -val);
            }
            break;
        default:
            break;
    }
}


/**
 * @brief   定时器 16 初始化（输入捕获）
 *
 * @note    内部时钟频率 CK_PSC 为 170MHz，则由以下公式：
 *              PWM 频率 = CK_PSC / (PSC + 1) / (ARR + 1)
 *              PWM 占空比 = CCR / (ARR + 1)
 *              PWM 分辨率 = 1 / (ARR + 1)
 *          得：
 *              ARR + 1 = 100
 *              PSC + 1 = 1700000
 *
 *          定时器 TIM16 的 1 个通道如下：
 *          | PIN  |   AF1     |    AF4     |
 *          |--------------------------------
 *          | PA6  | TIM16_CH1 |            |
 *          | PA12 | TIM16_CH1 |            |
 *          |--------------------------------
 *          | PB4  | TIM16_CH1 |            |
 *          | PB8  | TIM16_CH1 |            |
 *          | PE0  |           | TIM16_CH1  |
 *          |--------------------------------
 * @param   无
 * @retval  无
 */
void PD_H_TIM16_ICInit(void) {
    // 使能时钟
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM16);

    // 配置 GPIO
    // 配置 PA6 的 AF1 为 TIM16_CH1 的输入引脚
    PD_H_GPIO_TIM16_Init();

    // 设置内部时钟源
    LL_TIM_SetClockSource(TIM16, LL_TIM_CLOCKSOURCE_INTERNAL);

    // 配置时基单元
    LL_TIM_InitTypeDef TIM_InitStruct = {0};
    TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; // 滤波采样频繁的分频系数
    TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
    TIM_InitStruct.Prescaler = 170 - 1;    // PSC
    TIM_InitStruct.Autoreload = 65536 - 1; // ARR
    TIM_InitStruct.RepetitionCounter = 0;  // 重复计数器
    LL_TIM_Init(TIM16, &TIM_InitStruct);

    // 配置输入捕获单元
    LL_TIM_IC_InitTypeDef TIM_IC_InitStruct;
    LL_TIM_IC_StructInit(&TIM_IC_InitStruct);
    TIM_IC_InitStruct.ICPolarity = LL_TIM_IC_POLARITY_RISING;
    TIM_IC_InitStruct.ICActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
    TIM_IC_InitStruct.ICPrescaler = LL_TIM_ICPSC_DIV1;
    TIM_IC_InitStruct.ICFilter = 0xF;
    LL_TIM_IC_Init(TIM16, LL_TIM_CHANNEL_CH1, &TIM_IC_InitStruct);

    LL_TIM_SetTriggerInput(TIM16, LL_TIM_TS_TI1FP1);
    LL_TIM_SetSlaveMode(TIM16, LL_TIM_SLAVEMODE_RESET);

    // 其它寄存器使能
    LL_TIM_EnableCounter(TIM16);
}

/**
 * @brief   定时器 16 获取输入频率
 *
 * @note    无
 * @retval  输入信号频率
 */
uint32_t PD_H_TIM16_GetFreq(void) {
    // 测周法中，频率 = 标准频率 / 计次数。而标准频率为预分步后的内部时钟频率
    return 1000000 / (LL_TIM_IC_GetCaptureCH1(TIM16) + 1);
}

/**
 * @brief   定时器 16 获取输入占空比
 *
 * @note    无
 * @retval  输入信号占空比
 */
uint32_t PD_H_TIM16_GetDuty(void) {
    // 占空比 Duty = CCR2 / CCR1 * 100，这里不执行+1的操作也可
    return (LL_TIM_IC_GetCaptureCH2(TIM16) + 1) * 100 / (LL_TIM_IC_GetCaptureCH1(TIM16) + 1);
}


/**
 * @brief   定时器 1/8 初始化（编码器接口）
 *
 * @note
 *          定时器 TIM1 的 4 个通道如下：
 *          | PIN  |    AF2   |    AF6   |    AF11  |
 *          |----------------------------------------
 *          | PA8  |          | TIM1_CH1 |          |
 *          | PC0  | TIM1_CH1 |          |          |
 *          | PE9  | TIM1_CH1 |          |          |
 *          |----------------------------------------
 *          | PA9  |          | TIM1_CH2 |          |
 *          | PC1  | TIM1_CH2 |          |          |
 *          | PE11 | TIM1_CH2 |          |          |
 *          |----------------------------------------
 *          | PA10 |          | TIM1_CH3 |          |
 *          | PC2  | TIM1_CH3 |          |          |
 *          | PE13 | TIM1_CH3 |          |          |
 *          |----------------------------------------
 *          | PA11 |          |          | TIM1_CH4 |
 *          | PC3  | TIM1_CH4 |          |          |
 *          | PE14 | TIM1_CH4 |          |          |
 *          |----------------------------------------
 *
 *          定时器 TIM8 的 4 个通道如下：
 *          | PIN  |    AF2   |    AF4   |    AF5   |    AF10  |
 *          |--------------------------------------------------|
 *          | PA15 | TIM8_CH1 |          |          |          |
 *          | PB6  |          |          | TIM8_CH1 |          |
 *          | PC6  |          | TIM8_CH1 |          |          |
 *          |--------------------------------------------------|
 *          | PA14 |          |          | TIM8_CH2 |          |
 *          | PB8  |          |          |          | TIM8_CH2 |
 *          | PC7  |          | TIM8_CH2 |          |          |
 *          |--------------------------------------------------|
 *          | PB9  |          |          |          | TIM8_CH3 |
 *          | PC8  |          | TIM8_CH3 |          |          |
 *          |--------------------------------------------------|
 *          | PC9  |          | TIM8_CH4 |          |          |
 *          | PD1  |          | TIM8_CH4 |          |          |
 *          |--------------------------------------------------|
 * @retval  无
 */
void PD_H_TIM8_EncoderInit(void) {
    // 使能时钟
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM8);

    // 配置 GPIO
    // 配置 PB6/PB8 为 TIM1_CH1/2 的输入引脚
    PD_H_GPIO_TIM8_Init();

    // 设置内部时钟源
    // LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL);

    // 配置时基单元
    LL_TIM_InitTypeDef TIM_InitStruct = {0};
    TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; // 滤波采样频繁的分频系数
    TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
    TIM_InitStruct.Prescaler = 1 - 1;      // PSC 不分频
    TIM_InitStruct.Autoreload = 65536 - 1; // ARR 最大的自动重装值
    TIM_InitStruct.RepetitionCounter = 0;  // 重复计数器
    LL_TIM_Init(TIM8, &TIM_InitStruct);

    // 配置编码器接口
    LL_TIM_ENCODER_InitTypeDef TIM_ENCODER_InitStruct;
    LL_TIM_ENCODER_StructInit(&TIM_ENCODER_InitStruct);
    TIM_ENCODER_InitStruct.EncoderMode = LL_TIM_ENCODERMODE_X4_TI12;

    TIM_ENCODER_InitStruct.IC1Polarity = LL_TIM_IC_POLARITY_RISING;
    TIM_ENCODER_InitStruct.IC1ActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
    TIM_ENCODER_InitStruct.IC1Prescaler = LL_TIM_ICPSC_DIV1;
    TIM_ENCODER_InitStruct.IC1Filter = LL_TIM_IC_FILTER_FDIV1_N8;

    TIM_ENCODER_InitStruct.IC2Polarity = LL_TIM_IC_POLARITY_RISING;
    TIM_ENCODER_InitStruct.IC2ActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
    TIM_ENCODER_InitStruct.IC2Prescaler = LL_TIM_ICPSC_DIV1;
    TIM_ENCODER_InitStruct.IC2Filter = LL_TIM_IC_FILTER_FDIV1_N8;
    LL_TIM_ENCODER_Init(TIM8, &TIM_ENCODER_InitStruct);

    // 其它寄存器使能
    LL_TIM_EnableCounter(TIM8);
}

/**
 * @brief   定时器 16 获取输入频率
 *
 * @note    无
 * @retval  输入信号频率
 */
int16_t PD_H_TIM8_GetEncoder(void) {
    const int16_t temp = LL_TIM_GetCounter(TIM8);
    LL_TIM_SetCounter(TIM8, 0);
    return temp;
}


/** endregion public function region */


/** region private function region */

/** endregion private function region */
